package com.flydog.taskManager.service.impl;

import com.flydog.taskManager.common.converter.ProcessStatusConverter;
import com.flydog.taskManager.common.converter.RepeatModeConverter;
import com.flydog.taskManager.dto.PeriodicTaskParam;
import com.flydog.taskManager.dto.ProcessStatus;
import com.flydog.taskManager.entity.PeriodicTask;
import com.flydog.taskManager.entity.PeriodicTaskEndTime;
import com.flydog.taskManager.entity.TaskBrief;
import com.flydog.taskManager.repository.PeriodicTaskEndTimeRepository;
import com.flydog.taskManager.repository.PeriodicTaskRepository;
import com.flydog.taskManager.repository.TaskBriefRepository;
import com.flydog.taskManager.security.config.SecurityUtil;
import com.flydog.taskManager.service.PeriodicTaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author caoweidong
 * @version 0.0.0
 * @create 2021/6/18 10:31
 */
@Service
@Slf4j
public class PeriodicTaskServiceImpl implements PeriodicTaskService {
    @Autowired
    PeriodicTaskRepository periodicTaskRepository;
    @Autowired
    RepeatModeConverter repeatModeConverter;
    @Autowired
    SecurityUtil securityUtil;
    @Autowired
    PeriodicTaskEndTimeRepository endTimeRepository;
    @Autowired
    ProcessStatusConverter processStatusConverter;
    @Autowired
    TaskBriefRepository briefRepository;

    @Override
    public PeriodicTask create(PeriodicTaskParam param) {
        PeriodicTask periodicTask = new PeriodicTask();
        BeanUtils.copyProperties(param, periodicTask);
        periodicTask.setClassify(1);
        periodicTask.setRepeatMode(repeatModeConverter.convertToEntityAttribute(param.getRepeatMode()));
        periodicTask.initTaskStatus(Calendar.getInstance());
        periodicTask.setUserId(securityUtil.getAuthUserId());
        PeriodicTask savedTask = periodicTaskRepository.save(periodicTask);
        savePeriodEndTime(savedTask);
        return savedTask;
    }

    @Override
    public List<PeriodicTask> listAll() {
        Long userId = securityUtil.getAuthUserId();
        return periodicTaskRepository.findByUserId(userId);
    }

    @Override
    public List<PeriodicTask> refreshStatus(Calendar data) {
        List<PeriodicTask> periodicTasks = periodicTaskRepository.findDistinctByPeriodEndTimeLessThanEqual(data);
        List<PeriodicTask> changedTask = new ArrayList<>();
        for(PeriodicTask task : periodicTasks) {
            task.refreshTaskStatus(data);
            PeriodicTask savedTask = periodicTaskRepository.save(task);
            changedTask.add(savedTask);
        }
        return changedTask;
    }

    @Override
    public PeriodicTask update(Long id, PeriodicTaskParam param) {
        Optional<PeriodicTask> optionalTask = periodicTaskRepository.findById(id);
        if (optionalTask.isPresent()) {
            PeriodicTask periodicTask = optionalTask.get();
            BeanUtils.copyProperties(param, periodicTask);
            periodicTask.setRepeatMode(repeatModeConverter.convertToEntityAttribute(param.getRepeatMode()));
            periodicTask.refreshTaskStatus(Calendar.getInstance());
            return periodicTaskRepository.save(periodicTask);
        }
        return null;
    }

    @Override
    public Set<Long> delete(Long[] ids) {
        Set<Long> deleteIds = new HashSet<>();
        for (Long id: ids) {
            Optional<PeriodicTask> optionalPeriodicTask = periodicTaskRepository.findById(id);
            if (optionalPeriodicTask.isPresent()) {
                deleteIds.add(id);
                List<TaskBrief> briefs = briefRepository.findByPeriodicTaskIdOrderByCreateTimeDesc(id);
                briefRepository.deleteAll(briefs);
                periodicTaskRepository.delete(optionalPeriodicTask.get());
            }
        }
        return deleteIds;
    }

    @Override
    public Optional<PeriodicTask> getItem(Long id) {
        return periodicTaskRepository.findById(id);
    }

    @Override
    public PeriodicTask updateCurrentStatus(Long id, int status) {
        Optional<PeriodicTask> optionalPeriodicTask = periodicTaskRepository.findById(id);
        if (optionalPeriodicTask.isPresent()) {
            PeriodicTask periodicTask = optionalPeriodicTask.get();
            ProcessStatus processStatus = processStatusConverter.convertToEntityAttribute(status);
            periodicTask.setCurrStatus(processStatus);
            TaskBrief taskBrief = new TaskBrief();
            taskBrief.setPeriodicTaskId(periodicTask.getId());
            taskBrief.setSubject("完成本周期");
            taskBrief.setBrief("用户设置本周期s工作完成");
            taskBrief.setCreateTime(Calendar.getInstance().getTime());
            briefRepository.save(taskBrief);
            return periodicTaskRepository.save(periodicTask);
        }
        return null;
    }

    @Override
    public List<PeriodicTask> listPeriodEndBetween(Calendar begin, Calendar end) {
        return periodicTaskRepository.findByPeriodEndTimeBetweenAndUserIdOrderByPeriodEndTimeDesc(begin, end, securityUtil.getAuthUserId());
    }

    /**
     * 将周期性工作的周期结束时间存入数据库，方便后期统计。
     * 数据库存储的为，季度、半年和年周期的结束时间，日、周、月的方便计算没有存。
     * @param savedTask 保存后的周期性工作
     */
    private void savePeriodEndTime(PeriodicTask savedTask) {
        List<PeriodicTaskEndTime> endTimes = savedTask.getRepeatMode().getPeriodEndTimeList(savedTask.getEnd(), savedTask.getRepeatNum()).stream()
                .map(periodEndTime -> {
                    PeriodicTaskEndTime periodicTaskEndTime = new PeriodicTaskEndTime();
                    periodicTaskEndTime.setPeriodEndTime(periodEndTime);
                    periodicTaskEndTime.setPeriodTaskId(savedTask.getId());
                    return periodicTaskEndTime;
                }).collect(Collectors.toList());
        endTimeRepository.saveAll(endTimes);

    }
}
